/******************************************************************************
 * Copyright (C) 2023 Advanced Micro Devices, Inc. All Rights Reserved.
 * SPDX-License-Identifier: MIT
 ******************************************************************************/
/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 */

#include "LED_Ctrl.h"
#include "platform.h"
#include "xgpio.h"
#include "xil_printf.h"
#include "xparameters.h"
#include <stdio.h>

#define CTRL_MODE 1
// set 1:led=sw&btn
// other:led=sw|btn

int init_XGpio(XGpio *InstancePtr, UINTPTR BaseAddress);
void show_Status(u32 SwitchInput, u32 ButtonInput, u32 LedOutput);
void set_Led(u32 *LedOutput, u32 SwitchInput, u32 ButtonInput);

int main() {
  init_platform();

  print("Hello World\n\r");
  print("Successfully ran Hello World application");

  // init XGPIO device
  XGpio Switch, Button;
  if (init_XGpio(&Switch, XPAR_DIP_SWITCH_GPIO_BASEADDR) != XST_SUCCESS) {
    return XST_FAILURE;
  }
  if (init_XGpio(&Button, XPAR_PUSH_BUTTON_GPIO_BASEADDR) != XST_SUCCESS) {
    return XST_FAILURE;
  }

  // get the Input of Switch and Button
  u32 SwitchInput = 0, ButtonInput = 0, LedOutput;
  while (1) {
    SwitchInput = XGpio_DiscreteRead(&Switch, 1);
    ButtonInput = XGpio_DiscreteRead(&Button, 1);

    set_Led(&LedOutput, SwitchInput, ButtonInput);
    show_Status(SwitchInput, ButtonInput, LedOutput);
    LED_CTRL_mWriteReg(XPAR_LED_CTRL_GPIO_BASEADDR,
                       LED_CTRL_S00_AXI_SLV_REG1_OFFSET, LedOutput);
  }

  print("init completed!\r\n");

  cleanup_platform();
  return 0;
}

int init_XGpio(XGpio *InstancePtr, UINTPTR BaseAddress) {
  xil_printf("init XGPIO device with BaseAddress = %x\n\r", BaseAddress);
  XGpio_Config *Config = XGpio_LookupConfig(BaseAddress);
  return XGpio_CfgInitialize(InstancePtr, Config, Config->BaseAddress);
}

int get_bit(u32 num, size_t index) {
  // get the index bit of num
  return (num & (1 << index)) >> index;
}

void show_4bit(u32 num) {
  for (size_t i = 0; i < 4; i++) {
    xil_printf("%d", get_bit(num, i));
  }
  print("\r\n");
  return;
}

void show_Status(u32 SwitchInput, u32 ButtonInput, u32 LedOutput) {
  static u32 previousSwitchInput = -1, previousButtonInput = -1;
  if (previousSwitchInput == SwitchInput &&
      previousButtonInput == ButtonInput) {
    return;
  }

  static first_show = 1;
  if (first_show) {
    first_show = 0;
  } else {
    xil_printf("\033[3F");
  }

  previousSwitchInput = SwitchInput;
  previousButtonInput = ButtonInput;
  xil_printf("SwitchInput: %2d<==>", SwitchInput);
  show_4bit(SwitchInput);
  xil_printf("ButtonInput: %2d<==>", ButtonInput);
  show_4bit(ButtonInput);
  xil_printf("LedOutput: %2d<==>", LedOutput);
  show_4bit(LedOutput);
}

void set_Led(u32 *LedOutput, u32 SwitchInput, u32 ButtonInput) {
  switch (CTRL_MODE) {
  case 1:
    *LedOutput = SwitchInput & ButtonInput;
    break;
  default:
    *LedOutput = SwitchInput | ButtonInput;
    break;
  }
}